home *** CD-ROM | disk | FTP | other *** search
/ Mac100% 1998 November / MAC100-1998-11.ISO.7z / MAC100-1998-11.ISO / オンラインソフト定点観測 / ユーティリティ / Mops 3.2.sea / Mops 3.2 / Mops source / PPC source / cg2 < prev    next >
Text File  |  1998-05-19  |  44KB  |  1,656 lines

  1. marker m__cg2
  2.  
  3.  
  4. PPC?
  5. [IF]
  6. false    constant    debug?
  7. false    constant    cascadeTest?
  8. [ELSE]
  9. false    constant    debug?
  10. false    constant    cascadeTest?
  11. [THEN]
  12.  
  13.  
  14. (* This file handles the basic arithmetic and logical stuff, including
  15.    optimizations such as cascading (combining arithmetic ops) and strength
  16.    reduction.  Also branch resolution.
  17. *)
  18.  
  19.  
  20. (*
  21. CASCADE&MATCH? is called if we have an op which could possibly be combined with
  22. a preceding op - such a literal add where the other operand was also a literal
  23. add.  If it makes sense to combine the ops into a single op we do so, by deleting
  24. the earlier op and suitably modifying the new one.  After this we check for a
  25. match with a value already in the regs.  If there's a match, we generate a new
  26. reference to the matching op (and so generate no code).  In this case we return
  27. true to show that there's nothing more to do.  Otherwise we return false.
  28. Note that a false return doesn't mean we didn't do a cascade - but in this case
  29. we completely handle the cascade here so don't need to notify the caller.
  30.  
  31. On entry the new op we're looking at is in theOD.  (We do it this way because
  32. we mightn't have allocated a register for it yet.)  In the case where one operand
  33. is literal, it's always in B_opnd of theOD.  If this is a fetch or store, it will
  34. actually be zero.
  35.  
  36. We also assume references to the operands are in opnd1 and opnd2.  The idea of this
  37. is that if we cascade or in some way change the operand reg(s), we'll change the
  38. corresponding reference, so the caller will free: the right reg when it's finished.
  39. *)
  40.  
  41.  
  42. 0    value    antec#        ¥ the reg# of the operand of the antecedent op, which
  43.                         ¥  might be deleted if we cascade.
  44.  
  45.  
  46. ¥ OK_for_cascade? runs a series of checks on the GPR whose number is in antec#,
  47. ¥  to see if a cascade is safe.  It returns the appropriate flag.
  48.  
  49. objPtr    cas_regs  class_is ODs_class
  50.  
  51. : OK_FOR_CASCADE?  { ¥ antecedentCDP -- b }
  52.  
  53.     antec# select: cas_regs            ¥ select the operand GPR
  54.     get: ivar> opCDP in cas_regs  -> antecedentCDP
  55.  
  56.     false
  57.  
  58.     cascadeTest? if
  59.         ." ok_for_cascade? called on:"  print: cas_regs  cr
  60.     then
  61.  
  62. ¥ we won't cascade if it would cross a basic block boundary - this would
  63. ¥  bristle with problems, so isn't worth worrying about.  But note we
  64. ¥  ignore backstop_CDP here, since we're not doing any hoisting so 
  65. ¥  checking for a BB boundary is sufficient.  This also allows
  66. ¥  cascading to work at the start of defns, where the initial regs have
  67. ¥  zero in their opCDP fields, since we initialize basic_block_start to
  68. ¥  zero at the start of defns.
  69.  
  70.     get: ivar> opCDP in cas_regs  basic_block_start  u< ?EXIT
  71.  
  72. ¥ we can't cascade an op on a special reg - if it is, presumably
  73. ¥  we need the result and can't tamper with it, regardless of its refcnt.
  74.  
  75.     get: ivar> special? in cas_regs  ?EXIT
  76.  
  77. ¥ and we can't cascade if the operand's refcnt is > 1 (which is *this* ref) - if
  78. ¥  there are any others, we need that result, so mustn't clobber that op.
  79.  
  80.     get: ivar> refcnt in cas_regs  1 > ?EXIT
  81.  
  82. ¥ and we can't cascade if there was another use of that reg between its op and
  83. ¥  here - this is the same as an extra ref, except that it's already been retired.
  84.  
  85.     get: ivar> lastRefCDP in cas_regs
  86.     get: ivar> opCDP in cas_regs  u>  ?EXIT
  87.  
  88. ¥ and we can't cascade if one of the antecedent's operand regs has changed
  89. ¥  between there and here, which would prevent us validly recompiling here.
  90.  
  91.     Atype: cas_regs  gprRef =
  92.     IF    Agpr: cas_regs  select: cas_regs
  93.         get: ivar> opCDP in cas_regs
  94.         antecedentCDP u>
  95.         antec# select: cas_regs                ¥ restore selection
  96.         ?EXIT
  97.     THEN
  98.     
  99.     Btype: cas_regs  GPRRef =
  100.     IF    Bgpr: cas_regs  select: cas_regs
  101.         get: ivar> opCDP in cas_regs
  102.         antecedentCDP u>
  103.         antec# select: cas_regs                ¥ restore selection
  104.         ?EXIT
  105.     THEN
  106.  
  107. ¥ if we got here, it's OK!
  108.  
  109.     drop  true
  110. ;
  111.  
  112.  
  113. : CanBeMask?  { litVal ¥ mEnd ones? n -- mBegin mEnd true  | -- false }
  114.  
  115.     litVal NIF  0 0  true  EXIT  THEN
  116.     litVal -1 = IF  0 31 true  EXIT  THEN        ¥ they're the easy ones
  117.  
  118.     false -> ones?        ¥ nothing scanned yet, or just 0's
  119.     31 -> n
  120.     BEGIN    litVal
  121.     WHILE    litVal 1 and
  122.             NIF                ¥ next bit is a zero
  123.                 ones?
  124.                 IF            ¥ we were scanning ones and got a zero.  There
  125.                             ¥  must be more ones left (or we wouldn't have
  126.                             ¥  continued the loop).  So it's not a mask.
  127.                     false  EXIT
  128.                 THEN
  129.             ELSE            ¥ next bit is a one
  130.                 ones?
  131.                 NIF            ¥ we were scanning zeros and got a 1.  Must be the
  132.                             ¥  first one, so we mark its position.
  133.                     n -> mEnd  true -> ones?
  134.                 THEN
  135.             THEN
  136.             1 --> n
  137.             litVal 1 >>  -> litVal
  138.     REPEAT
  139.     
  140. ¥ if we got here, it's OK as a mask.  n is one less than the bit number
  141. ¥  of the first 1.
  142.     n 1+  mEnd  true
  143. ;
  144.  
  145.  
  146. : TRY_CASCADE_SHIFT&MASK  { litVal ¥ mBegin mEnd -- b }
  147.     false
  148.     
  149.     OK_for_cascade?  0EXIT
  150.     litVal canBeMask?  0EXIT
  151.  
  152.     -> mEnd  -> mBegin
  153.  
  154.     drop                                ¥ drop false flag
  155.     cascadeTest? if
  156.         ." cascading shift&mask on:" print: gprs
  157.         ." lit val we're ANDing: $" litval .h  cr cr
  158.     then
  159.  
  160.     get: ivar> maskBegin in GPRs  mBegin  max  -> mBegin
  161.     get: ivar> maskEnd     in GPRs  mEnd    min  -> mEnd
  162.  
  163.     addr: GPRs  ->: theOD
  164.     mBegin put: ivar> maskBegin in theOD
  165.     mEnd   put: ivar> maskEnd   in theOD
  166.  
  167.     [ cascadeTest? ] [if]
  168.         ." new theOD:"  print: theOD cr
  169.     [then]
  170.  
  171.     noRef >refType: opnd1            ¥ opnd1 is now gone - reg mustn't get free: from caller
  172.     true
  173. ;
  174.  
  175.  
  176. (*    check_complemented_operand looks for situations where we can generate
  177.     an andc or an orc by cascading an AND or OR with a preceding NOT.  We can
  178.     do this if they weren't immediate.  But it has to be the B operand which
  179.     gets complemented, so we switch them if necessary.
  180. *)
  181.  
  182. : CHECK_COMPLEMENTED_OPERAND  { ¥ complement? -- b }
  183.  
  184.     debug? if
  185.         ." check_complemented_operand called" cr
  186.     then
  187.     
  188.     false
  189.     false -> complement?
  190.  
  191. ¥ the A operand GPR is already selected
  192.  
  193.     get: ivar> opType in GPRs  otNOT  =
  194.     IF    true -> complement?
  195.         Bgpr: theOD  >Agpr: theOD        ¥ Bgpr will be set below
  196.     ELSE
  197.         Bgpr: theOD  select: GPRs
  198.         get: ivar> opType in GPRs  otNOT =
  199.         IF    true -> complement?
  200.             current: GPRs  -> antec#        ¥ it's different now
  201.         THEN
  202.     THEN
  203.  
  204.     antec# select: GPRs                        ¥ normal selection
  205.  
  206.     complement?  0EXIT                        ¥ out if no NOT
  207.     OK_for_cascade?  0EXIT                    ¥ or if NOT reg can't be deleted
  208.  
  209.     drop                                    ¥ drop the false flag
  210.     cascadeTest? if
  211.         ." cascading NOT and AND/OR - deleting " current: GPRs . cr
  212.         ." new OD in theOD:"  print: theOD cr
  213.     then
  214.  
  215.     Agpr: GPRs  >Bgpr: theOD            ¥ operand to be complemented
  216.     not: ivar> complB? in theOD
  217.  
  218.     Agpr: theOD  >gpr: opnd2  noRef >reftype: opnd1
  219.                                         ¥ only one reg to get free: from caller
  220.     true
  221. ;
  222.  
  223.  
  224. : TRY_CASCADE_AND  ( -- b )
  225.     Btype: theOD
  226.     CASE[    litRef    ]=>        get: ivar> opType in GPRs  otShift&mask =
  227.                             IF      Blit: theOD  try_cascade_shift&mask
  228.                             ELSE    false
  229.                             THEN
  230.  
  231.         [    gprRef    ]=>        check_complemented_operand
  232.         DEFAULT=>        drop  false
  233.     ]CASE
  234. ;
  235.  
  236.  
  237. : TRY_CASCADE_OR  ( -- b )
  238.     Btype: theOD  gprRef =  NIF  false  EXIT  THEN
  239.     check_complemented_operand
  240. ;
  241.  
  242.  
  243. (*    try_cascade_not checks for situations where we can generate a nand or a nor,
  244.     by cascading a NOT with a preceding AND, OR or XOR.  We can do this if
  245.     they weren't immediate.
  246. *)
  247.  
  248. : TRY_CASCADE_NOT  { ¥ prevOp -- b }
  249.  
  250.     false
  251.  
  252.     get: ivar> complB? in GPRs  ?EXIT        ¥ or if it's an andc or orc (can't complement
  253.                                             ¥ the result - we don't have "nandc" or "norc")
  254.     Agpr: theOD  select: GPRs
  255.     get: ivar> opType in GPRs  -> prevOp    ¥ grab preceding op
  256.     prevOp otAND =  prevOp otOR = or
  257.     prevOp otXOR = or  0EXIT                ¥ out if wrong sort
  258.     Atype: GPRs  gprRef =  0EXIT            ¥ out if either of its operands wasn't
  259.     Btype: GPRs  gprRef =  0EXIT            ¥  a GPR
  260.  
  261.     drop                                    ¥ OK, we'll do it.  Drop false flag
  262.     current: GPRs  -> antec#                ¥ may have changed
  263.  
  264.     [ cascadeTest? ] [if]
  265.         ." cascading NOT with earlier op:" print: gprs
  266.         ." theOD:"  print: theOD  cr cr
  267.     [then]
  268.  
  269.     addr: GPRs  ->: theOD                    ¥ copy op to theOD (which is where we need it)
  270.     not: ivar> complResult? in theOD        ¥ and set "complement result" flag
  271.  
  272.     noRef >refType: opnd1            ¥ opnd1 is now gone - reg mustn't get free: from caller
  273.     true
  274. ;
  275.     
  276.  
  277. : TRY_CASCADE_ADD  { op ¥ litVal Btype -- b }
  278.  
  279.     false
  280.  
  281.     Btype: theOD  litRef = 0EXIT            ¥ out if this op not literal
  282.     get: ivar> opType in GPRs otAdd = 0EXIT    ¥ or if prev op not add
  283.     OK_for_cascade?  0EXIT                    ¥ or if GPR op can't be deleted
  284.  
  285.     Blit: theOD  -> litVal
  286.     Btype: GPRs  -> Btype
  287.  
  288.     op otAdd =
  289.     IF                                    ¥ and if THIS op is add, the other add must
  290.         Btype litRef <> ?EXIT            ¥ be literal.
  291.  
  292.     ELSE    ¥ For fetch or store, we can add 2 regs, since indexed mode exists, but
  293.             ¥  the literal we're adding must be zero.  Note the only possibility
  294.             ¥  that can come up here is the antecedent op adding 2 regs, and this
  295.             ¥  op fetching/storing using the result reg and a literal zero.  The
  296.             ¥  antecedent op can't be a literal add of zero, since we never compile
  297.             ¥  those!
  298.         
  299.         Btype gprRef =
  300.         IF        litVal  ?EXIT
  301.         ELSE    Btype litRef <> ?EXIT
  302.         THEN
  303.     THEN
  304.                                             
  305.     get: ivar> special? in GPRs  ?EXIT        ¥ and only on a temp register - if on another
  306.                                             ¥ another reg, we need the value, so can't
  307.                                             ¥ delete the op.
  308.  
  309. ¥ Right, if we got here we'll do the cascade!
  310.  
  311.     drop                                    ¥ drop false flag
  312.  
  313.     cascadeTest? if
  314.         ." cascading adds on:" print: gprs
  315.         ." lit val we're adding: " litval .  cr
  316.         ." theOD:"  print: theOD  cr cr
  317.     then
  318.  
  319.     Btype: GPRs  GPRRef =
  320.     IF    Bgpr: GPRs  >Bgpr: theOD
  321.         noRef >refType: opnd2
  322.     ELSE
  323.         Blit: GPRs  ++> litVal                ¥ new literal value
  324.         litVal >Blit: theOD
  325.     THEN
  326.     Agpr: GPRs  >Agpr: theOD
  327.  
  328.     noRef >refType: opnd1            ¥ opnd1 is now gone - reg mustn't get free: from caller
  329.     true
  330. ;
  331.  
  332.  
  333. : TRY_CASCADE_FMADD  { op ¥ doit? subop add_fpr# ^ref_to_clear -- b }
  334.  
  335.     false -> doit?
  336.     multiply-add? NIF  false  EXIT  THEN    ¥ out if we're not doing it
  337.  
  338.     FPRs -> cas_regs  nilP -> ^ref_to_clear
  339.     op otFsub = if 1 else 0 then  -> subop
  340.  
  341. ¥ note: we need to check both the A and B operands of this op.  If either
  342. ¥  is a multiply, we might be able to generate a fmadd.
  343.  
  344.     Areg: theOD  dup -> antec#
  345.     select: FPRs
  346.     
  347.     cascadetest? if
  348.         ." try_cascade_fmadd here." cr
  349.         ." theOD:" print: theOD cr
  350.         ." Looking for 42 (otFmul) in A opnd FPR:" print: FPRs cr
  351.         dasm
  352.     then
  353.  
  354.     get: ivar> opType in FPRs otFmul =
  355.     IF  OK_for_cascade?
  356.         IF    get: ivar> special? in FPRs
  357.             NIF        true -> doit?
  358.                     Breg: theOD -> add_fpr#
  359.                     opnd1 -> ^ref_to_clear
  360.             THEN
  361.         THEN
  362.     THEN
  363.     
  364.     doit?
  365.     NIF        ¥ can't do it on the A operand - let's try B...
  366.         Bfpr: theOD  dup -> antec#
  367.         select: FPRs
  368.  
  369.         cascadetest? if
  370.             ." trying B opnd FPR:" print: FPRs cr
  371.         then
  372.  
  373.         get: ivar> opType in FPRs otFmul =
  374.         IF  OK_for_cascade?
  375.             IF    get: ivar> special? in FPRs
  376.                 NIF        ¥ yep, we can do it, but if it's mult-and-subtract,
  377.                         ¥ the operands are reversed.
  378.                     true -> doit?
  379.                     subop 2* -> subop
  380.                     Areg: theOD -> add_fpr#
  381.                     opnd2 -> ^ref_to_clear
  382.                 THEN
  383.             THEN
  384.         THEN
  385.     THEN
  386.     
  387.     doit? NIF  false  EXIT  THEN        ¥ out with false if we can't do it at all
  388.                                             
  389. ¥ Right, if we got here we'll do the cascade!
  390.  
  391.     cascadeTest? if
  392.         ." cascading floating mult and add on:" print: fprs
  393.     then
  394.  
  395.     Areg: FPRs    >Afpr: theOD
  396.     Breg: FPRs    >Bfpr: theOD    ¥ these operands get multiplied
  397.     add_fpr#    >Cfpr: theOD    ¥ this one gets added/subtracted
  398.  
  399.     otFmadd  put: ivar> opType in theOD
  400.     subop  put: ivar> subtype in theOD
  401.  
  402.     cascadetest? if
  403.         ." theOD as set up for fmadd:"  print: theOD  cr
  404.         ." setting this operand ref to noRef: "  print: [ ^ref_to_clear ]  cr
  405.     then
  406.     
  407.     noRef  ^ref_to_clear >refType: class_as> reference
  408.                 ¥ either opnd1 or opnd2 is now gone - reg mustn't get free: from caller
  409.     true
  410. ;
  411.  
  412.  
  413. : TRY_CASCADE  { ¥ op atype -- }
  414.  
  415.     cascade? 0EXIT            ¥ straight out if cascading turned off
  416.  
  417.     GPRs -> cas_regs        ¥ normal default
  418.  
  419.     cascadeTest? if
  420.         ." try_cascade called with theOD:" print: theOD cr
  421.     then
  422.     
  423.     get: ivar> opType in theOD  -> op        ¥  op is the new op we're compiling
  424.  
  425. ¥ first we won't cascade if we're not handling that reg type:
  426.  
  427.     Atype: theOD -> atype
  428.     atype gprRef =
  429.     IF    ¥ we set the A operand as the initial default for the reg we'll replace
  430.         ¥  if we cascade, but we won't check it yet since it might be a GPR-GPR 
  431.         ¥  op and we might end up cascading on the other operand.
  432.  
  433.         Agpr: theOD  dup -> antec#
  434.         select: GPRs
  435.     
  436.     ELSE
  437.         atype fprRef =  0EXIT        ¥ out if not gprRef or fprRef
  438.     THEN
  439.  
  440.     op
  441.     SELECT[    otAdd        ],
  442.           [ otFetch        ],
  443.           [    otFPfetch    ],
  444.           [    otStore        ],
  445.           [ otFPstore    ]=>        op try_cascade_add
  446.  
  447.           [ otAnd        ]=>        try_cascade_and
  448.           [    otOr        ]=>        try_cascade_or
  449.           [    otNot        ]=>        try_cascade_not
  450.  
  451.           [    otFadd        ],
  452.           [    otFsub        ]=>        op try_cascade_fmadd
  453.                                           ¥ can change cas_regs to FPRs
  454.  
  455.             DEFAULT=>        drop false
  456.     ]SELECT
  457.     
  458.     cascadeTest? if
  459.         cr ." checking for cascade returns " dup . cr
  460.     then
  461.     
  462.     antec# select: cas_regs            ¥ antec# might have changed.  This should be
  463.                                     ¥  redundant, but you never know.
  464.  
  465.     cascadeTest? if
  466.         dup if    ." deleting: "  print: cas_regs cr
  467.                 ." new OD in theOD"  print: theOD cr
  468.             then
  469.     then
  470.     
  471.     IF    delete: cas_regs  THEN        ¥ if we cascaded, we delete the op we've made
  472.                                     ¥  redundant
  473. ;
  474.  
  475.  
  476. : CASCADE&MATCH?
  477.     try_cascade                    ¥ do the cascade if we can (and if we did,
  478.                                 ¥  theOD will have been appropriately modified
  479.     true match&allocate?
  480.     cascadeTest? if
  481.         ." calling match&allocate? returns " dup . cr
  482.     then
  483. ;
  484.  
  485.  
  486. (*
  487. STRENGTH_REDUCE? is called if we have an op where one of the operands is
  488. literal.  We may be able to strength-reduce the op to something simpler.
  489. Currently we just do one: if the op is a multiply, and the literal is a
  490. power of 2, we convert it to a shift.
  491.  
  492. If we change the op, we then, as usual, check for a match with an op
  493. already in the regs.  If there's a match, we return true to show that
  494. there's nothing more to do.  Otherwise we return false.
  495. *)
  496.  
  497. : STRENGTH_REDUCE?  { ¥ litVal #bits n -- }
  498.     operation otMul <> IF  false  EXIT  THEN
  499.     Blit: theOD  -> litVal  0 -> #bits  -1 -> n
  500.     litVal 0<=  IF  false  EXIT  THEN
  501.     BEGIN    litVal
  502.     WHILE    litVal 1 and  ++> #bits
  503.             1 ++> n
  504.             litVal 1 >>  -> litVal
  505.     REPEAT
  506.     #bits 1 <>  IF  false  EXIT  THEN
  507.     
  508. ¥ yes, it's a power of 2 - n gives the power.
  509.  
  510.     otShift -> operation  0 -> subOperation
  511.     operation  put: ivar> opType in theOD
  512.     subOperation  put: ivar> subType in theOD
  513.     n >Blit: theOD
  514.     true match&allocate? IF  true  ELSE  false  THEN
  515. ;
  516.  
  517.  
  518. (*    RegLit_as_2_instrns? is called from CompRegLit if the literal is > 16 bits.
  519.     We see if it can be done as one or two instructions.
  520.     
  521.     For AND, OR and XOR, the andi, ori and xori instructions have shifted
  522.     forms, which means that we can do the op in 2 instructions, or 1 if the 
  523.     lower 16 bits are zero.  For ADD, if the literal value isn't too large,
  524.     we can do the op as two literal adds.
  525.     
  526.     If we can do one of these optimizations, we do it here and return true.
  527.     Otherwise we return false.
  528.     
  529.     On entry, we've already allocated a result reg and res1 is a reference
  530.     to it.   If we return true, we might have found a match, and in that case
  531.     we make sure res1 indicates the new result, and we free the old result reg.
  532.     
  533.     Special note: if we need 2 instructions, we have a choice:
  534.     A.  Generate the ops using 2 separate registers
  535.     B.  Reuse the one reg.
  536.     
  537.     Under A, we would call compile: GPRs twice, targetting a different GPR.
  538.     Under B, we could handle the whole thing in the compile: method
  539.     of OD, and only call it once from here.  There are pros and cons either 
  540.     way.  B is a bit simpler.  But for ADD, we'll often get
  541.     called for address generation where the target addresses have a lot
  542.     of locality, and we might be able to re-use intermediate values if we
  543.     use A and do it a bit cleverly.  But for the logicals, we're much
  544.     less likely to be able to reuse the intermediate values and so we'd
  545.     be using an extra register for nothing.  So we'll use A for ADD, and 
  546.     B for the logicals.
  547. *)
  548.  
  549.  
  550. : RegLit_as_2_instrns?  { litVal ¥ op n1 n2 dest_gpr# temp_gpr# -- b }
  551.  
  552.     false
  553.  
  554.     refType: opnd1  GPRref <> ?EXIT        ¥ can't do it if it's not a GPR->GPR op
  555.     refType: res1    GPRref <> ?EXIT
  556.  
  557.     operation -> op
  558.     reg: res1  -> dest_gpr#  0 -> temp_gpr#
  559.     
  560.     op otAND =
  561.     IF                        ¥ we can do it for AND iff the lo 16 bits are zero
  562.         litVal $ FFFF and  ?EXIT        ¥ out if they're not
  563.         true
  564.     ELSE
  565.         op otOR =  op otXOR =  or        ¥ we can always do it for OR and XOR
  566.     THEN
  567.     
  568.     IF        ¥ it's a logical op and we're to use plan B
  569.         0 -> n1  litVal -> n2
  570.     ELSE
  571.         op otAdd =  0EXIT                    ¥ out if op isn't add (no literal subtract)
  572.         litVal 2/ $ fffffc00 and -> n1        ¥ halve the literal & round down to
  573.                                             ¥  1024-byte boundary to increase
  574.                                             ¥  chance of a match later
  575.         n1 true 16bits? nip  0EXIT            ¥ if THAT won't fit in 16 bits, nogo
  576.         litVal n1 -  -> n2                    ¥ subtract that from orig literal
  577.         n2 true 16bits? nip  0EXIT            ¥ if that won't fit in 16 bits, nogo
  578.     THEN
  579.     
  580. ¥ if we got here, we can do it!
  581.     
  582.     drop true                                ¥ we'll be returning true
  583.  
  584.     n1 IF            ¥ we only do this for ADD (plan A)
  585.         n1 >Blit: theOD
  586.         
  587.         true match&allocate?
  588.         IF
  589.             current: GPRs  -> temp_gpr#
  590.         ELSE
  591.             getFreeReg: GPRs -> temp_gpr#
  592.             theOD ->: GPRs  compile: GPRs    ¥  compile the 1st op
  593.         THEN
  594.     
  595.         temp_gpr# >Agpr: theOD                ¥ result of 1st op is source for 2nd
  596.     THEN
  597.  
  598.     n2 >Blit: theOD
  599.     true match&allocate?
  600.     IF                                    ¥ match on 2nd op - res1 now points
  601.                                         ¥  to the new result.
  602.         dest_gpr# select: GPRs  free: GPRs
  603.     ELSE
  604.         dest_gpr# dup select: GPRs  >gpr: res1
  605.                                         ¥ res1 may have been changed by
  606.                                         ¥  the first match&allocate? call
  607.         theOD ->: GPRs  compile: GPRs
  608.     THEN
  609.     
  610. ¥ finally, whether anything matched or not, we have to free the
  611. ¥  intermediate reg, if there was one:
  612.  
  613.     temp_gpr# ?dup IF  select: GPRs  free: GPRs  THEN
  614. ;
  615.  
  616.  
  617. : compCRCR
  618.     debug? if
  619.         ." compCRCR called to compile a CR op.  theOD:" cr
  620.         print: theOD
  621.     then
  622.  
  623.     false 0 0 CR_result
  624.     theOD ->: CRs
  625.     compile: CRs
  626.     cmpLT  >condition: res1
  627.             ¥ it's fairly arbitrary, actually, but must agree with what we
  628.             ¥ put ihto rD.  Easiest is bit# 0, 1 is true, which means
  629.             ¥ "less than", so that's what we use.
  630. ;
  631.  
  632.  
  633. ¥ compRegReg factors out some common code from dyadic_arith and monadic_arith.
  634. ¥ theOD is set up with the new op we're about to compile.
  635.  
  636. : compRegReg    
  637.     true match&allocate?  ?EXIT        ¥ if it matches a result we already
  638.                                     ¥  have, we reuse it
  639.                                     
  640.     cascade&match?  ?EXIT            ¥ If we can cascade it with a preceding
  641.                                     ¥  op, we do it and we're done
  642.  
  643. ¥ now one or both operands might be in CRs, so we have to check.
  644.  
  645.     debug? if
  646.         ." compRegReg - match&allocate? and cascade&match?" cr
  647.         ." both returned false.  TheOD:" print: theOD cr
  648.     then
  649.  
  650.     Atype: theOD  fprRef =
  651.     IF
  652.         1 fresults
  653.     ELSE
  654.         Atype: theOD  gprRef =
  655.         IF    Btype: theOD  dup gprRef =  swap noRef =  or
  656.             NIF    Bref: theOD  get_to_gpr?
  657.                              IF        ¥ changed, so we update opnd2 so it gets
  658.                                      ¥  freed properly by the caller.  New ref is
  659.                                      ¥  always left in res1 by get_to_gpr?
  660.                                  res1 ->: opnd2
  661.                              THEN
  662.             THEN
  663.         ELSE
  664.             Btype: theOD  dup gprRef =  swap noRef =  or
  665.             IF    Aref: theOD  get_to_gpr? IF  res1 ->: opnd1  THEN
  666.             ELSE
  667.                 compCRCR  EXIT
  668.             THEN
  669.         THEN
  670.  
  671.     ¥ if we got here, both operands are in regs, even if they weren't
  672.     ¥  to start with.
  673.  
  674.         1 results
  675.     THEN
  676.  
  677.     theOD ->: theRegs
  678.     compile: theRegs
  679. ;
  680.  
  681.  
  682. (*    compRegLit is a lot more complicated.  It's called from several places where
  683.     we're doing a dyadic op where one operand is literal.  There are a lot of
  684.     possible optimizations.
  685.  
  686.     Unlike compRegReg, theOD is not set up yet, since we have to do some checks
  687.     first.
  688.     
  689.     We enter with the lit in opnd2, and the other operand is opnd1.
  690.     We leave res1 indicating the result.  Note that we allocate the result
  691.     reg fairly early, and set up res1, which means that if we later find
  692.     a match or change the result reg for some reason, we need to free: res1.
  693. *)
  694.  
  695. objPtr    OP_resultReg  class_is OD
  696.  
  697.  
  698. : compRegLit  { ¥ reg# litVal sgnd? comp? -- }
  699.  
  700.     lit: opnd2  -> litVal
  701.  
  702.     clear: theOD  operation  put: ivar> opType in theOD
  703.     subOperation  put: ivar> subType in theOD
  704.  
  705.     operation  dup signed? -> sgnd?
  706.     dup otCMP =  swap otUCMP = or  -> comp?
  707.  
  708.     debug? if
  709.         cr
  710.         ." compRegLit - " cr
  711.         ." opnd1 " print: opnd1
  712.         ."  litVal " litVal . ."  sgnd? " sgnd? .  ."  comp? " comp? . cr
  713.         ." operation " operation .h cr
  714.         printall: cstk
  715.     then
  716.  
  717. ¥ First, there's no literal divide or multiply high instruction - so if
  718. ¥  we have this, we need to load the literal into a reg and change to
  719. ¥  a reg-reg op.
  720.  
  721.     operation otDiv =
  722.     operation otUDiv =  or
  723.     operation otMulh =  or
  724.     IF
  725.         theOD copyOD: tmpOD
  726.         litVal false  lit>gpr
  727.         tmpOD copyOD: theOD
  728.         opnd1  ->: ivar> A_opnd in theOD
  729.         res1   ->: ivar> B_opnd in theOD    ¥ this was set by lit>gpr
  730.         compRegReg   EXIT
  731.     THEN
  732.  
  733. ¥ Next, there's no literal subtract instruction - so in this case
  734. ¥  we need to negate the literal value and change the op to add.
  735.  
  736.     operation otSub =
  737.     IF    neg> litVal  otAdd -> operation  THEN
  738.  
  739.     operation  put: ivar> opType in theOD        ¥ may not have been set up, and
  740.                                                 ¥  in any case may have changed
  741.     reg: opnd1  -> reg#            ¥ may be a gpr or cr reference
  742.     litVal  >BLit: theOD
  743.  
  744. ¥ Now, we can get rid of some trivial cases.  Object binding and inline
  745. ¥ definitions can produce things like 0 +  or  -1 AND  for which we don't
  746. ¥ have to generate any code.  For these, we just set res1 and get out.
  747. ¥ The res1 result is either a literal -1 or 0, or it's a copy of opnd1.
  748. ¥ In the cases where we transfer opnd1 to res1, we clear opnd1 so that 
  749. ¥ its register doesn't get freed (we're still using it, of course).
  750.  
  751.     operation otAnd =
  752.     IF    litval
  753.         NIF    debug? if  ." anding zero - replacing with zero" cr  then
  754.             0 >lit: res1  free: opnd1  delete: opnd1  EXIT
  755.         ELSE
  756.             litval -1 =
  757.             IF    debug? if  ." anding -1 - moving opnd1 to res1" cr  then
  758.                 opnd1 ->: res1  clear: opnd1  EXIT
  759.             THEN
  760.         THEN
  761.     THEN
  762.  
  763.     operation otOr =
  764.     IF    litval
  765.         NIF    debug? if  ." oring 0 - moving opnd1 to res1" cr  then
  766.             opnd1 ->: res1  clear: opnd1  EXIT
  767.         ELSE
  768.             litval -1 =
  769.             IF    debug? if  ." oring -1 - replacing with -1" cr  then
  770.                 -1 >lit: res1  free: opnd1  delete: opnd1  EXIT
  771.             THEN
  772.         THEN
  773.     THEN
  774.  
  775.     operation otAdd =
  776.     IF    debug? if  ." adding 0 - moving opnd1 to res1" cr  then
  777.         litval NIF  opnd1 ->: res1  clear: opnd1  EXIT  THEN
  778.     THEN
  779.     
  780.     refType: opnd1
  781.  
  782.     SELECT[    gprRef    ]=>
  783.                 reg#  >Agpr: theOD
  784.                 true match&allocate? ?EXIT    ¥ if it already exists, we're done.
  785.  
  786.                 cascade&match?         ?EXIT    ¥ if we cascaded and it already exists
  787.                 Blit: theOD -> litVal        ¥ may have changed
  788.                 Agpr: theOD >gpr: opnd1        ¥ likewise
  789.  
  790.                 strength_reduce?  ?EXIT        ¥ if we strength-reduced & it alr exists
  791.     
  792.           [    CRref    ]=>            ¥ CR - lit operation - normally we'll have to
  793.                                   ¥  get the CR to a GPR first.  The only exceptions
  794.                                   ¥  are the degenerate cases where the op is a logical
  795.                                   ¥  or comparison, and the lit is -1 or 0.  At the
  796.                                   ¥  moment we won't bother with these optimizations
  797.                                   ¥  (which would probably be pretty rare anyway).
  798.                   reg# >Acr: theOD
  799.                 true match&allocate?  ?EXIT        ¥ if it already exists, we're done.
  800.  
  801.                   opnd1 cr>gpr  res1 ->: opnd1    ¥ cr>gpr frees the CR
  802.  
  803.                 debug? if
  804.                     ." opnd1 is CR - converted to: " print: opnd1 cr
  805.                 then
  806.                 
  807.                 gpr: opnd1  dup -> reg#  >Agpr: theOD
  808.  
  809.             DEFAULT=>  to_be_written  drop
  810.  
  811.     ]SELECT
  812.  
  813.     false -> check_OP_stores?        ¥ we must have this checking turned
  814.                                     ¥  off, since large_obj_array elements
  815.                                     ¥  don't have class pointers
  816.  
  817.     comp?
  818.     IF    false 0 0 CR_result        ¥ for comparisons, dest is a CR.  Get a CR result reg
  819.         addr: CRs  -> OP_resultReg
  820.         litVal sgnd? 16bits? nip
  821.         IF    theOD ->: CRs
  822.             compile: CRs  EXIT
  823.         THEN
  824.     ELSE
  825.         1 results        ¥ get a GPR result reg
  826.         addr: GPRs  -> OP_resultReg
  827.  
  828.         debug? if
  829.             ." result reg will be "  print: gprs  cr
  830.         then
  831.  
  832.         litVal sgnd? 16bits? nip
  833.         IF    theOD ->: GPRs
  834.             compile: GPRs
  835.             debug? if
  836.                 ." just compiled this reg:" print: GPRs
  837.                 printall: cstk
  838.             then
  839.             EXIT
  840.         THEN
  841.     THEN
  842.  
  843. (*    If we got to here, the literal was >16 bits.  We may have to load
  844.     the long literal into a register, then do a 2-reg op.  This will
  845.     take a total of 3 instructions.  But there are some other things
  846.     we can try:
  847.     
  848.     1.  If the operation is and, and the literal could be a mask, we
  849.     can replace the and with a rotate left (by zero) and mask.
  850.  
  851.     2.  If the operation is add, and, or or xor, we may be able
  852.     to do the op in 1 or 2 instructions.  This is handled by
  853.     regLit_as_2_instrns?.
  854.     
  855.     Note that at this point we've allocated the result reg, and it's
  856.     selected in GPRs.  If we match on a value in another reg, we'll
  857.     have to free the result reg we have now.
  858. *)
  859.  
  860.     operation otAND =
  861.     IF
  862.         litVal canBeMask?
  863.         IF    theOD ->: GPRs
  864.             otShift&mask    put: ivar> opType        in GPRs
  865.                             put: ivar> maskEnd        in GPRs
  866.                             put: ivar> maskBegin    in GPRs
  867.                         0    >lit: ivar> B_opnd        in GPRs        ¥ rotate by 0
  868.             compile: GPRs  EXIT
  869.         THEN
  870.     THEN
  871.  
  872.     litVal regLit_as_2_instrns?  ?EXIT        ¥ if we did it, we're done
  873.  
  874. ¥ Right, we have to compile a load of the long literal into a reg, then use the
  875. ¥  reg.  This case then becomes like a normal 2-reg op (see below)
  876.  
  877.     litVal setLit: theOD
  878.  
  879.     theOD  true  match?
  880.     IF    drop
  881.         debug? if
  882.             ." long lit matched on:" print: GPRs  .s
  883.         then
  884.         
  885.         allocate: GPRs
  886.         current: GPRs  dup -> reg#  >GPR: opnd2
  887.     ELSE
  888.         getFreeReg: GPRs                ¥ get reg we're going to load into
  889.         theOD  ->: GPRs
  890.         dup -> reg#  >GPR: opnd2
  891.         compile: GPRs                    ¥ compile load of the long lit
  892.     THEN
  893.  
  894.     debug? if
  895.         ." long lit was loaded - res1 before compiling op:" print: res1 cr
  896.         ." result reg:" print: OP_resultReg cr  .s
  897.     then
  898.  
  899.     gpr: opnd1    >Agpr: OP_resultReg
  900.     reg#        >Bgpr: OP_resultReg
  901.     operation put: ivar> opType in OP_resultReg  compile: OP_resultReg
  902.  
  903.     gpr: opnd2  select: GPRs  free: GPRs
  904.                                 ¥ free the temp reg we used for the lit
  905. ;
  906.  
  907.  
  908. ¥ nonCom_litReg is called from dyadic_arith when the first operand is literal
  909. ¥  and the second is in a register, and the op is non-commutative so we can't
  910. ¥  just swap the operands.  We load the literal into a reg and do a reg-reg op.
  911. ¥  (The code is similar to that near the start of compRegLit above, when we
  912. ¥  handle an operation that doesn't have a literal instruction.)
  913.  
  914. : NONCOM_LITREG  { ¥ litVal -- }
  915.     lit: opnd1  -> litVal
  916.     theOD copyOD: tmpOD
  917.     litVal false  lit>gpr
  918.     tmpOD copyOD: theOD
  919.     res1   ->: ivar> A_opnd in theOD    ¥ this was set by lit>gpr
  920.     opnd2  ->: ivar> B_opnd in theOD
  921.     compRegReg
  922. ;
  923.  
  924.  
  925. : COMMUTATIVE?  ( op -- b )
  926.     CASE[    otSub            ],
  927.         [    otDiv            ],
  928.         [    otUDiv            ],
  929.         [    otShift            ],
  930.         [    otShift&mask    ],
  931.         [    otTrap            ]=>        false
  932.         
  933.         DEFAULT=>                    drop true
  934.     ]CASE
  935. ;
  936.  
  937.  
  938. : FP_DYADIC_ARITH
  939.  
  940.     FPRs -> theRegs
  941.     2 foperands
  942.  
  943.     opnd1  ->: ivar> A_opnd in theOD
  944.     opnd2  ->: ivar> B_opnd in theOD
  945.     compRegReg
  946.     free: opnd1  free: opnd2
  947.     res1 fpush
  948.     GPRs -> theRegs        ¥ normal default - might be best to put it back
  949.  
  950.     debug? if
  951.         ." fp_dyadic_arith finished:" cr
  952.         ." cstk:  " printall: cstk cr
  953.         ." cstk2: " printall: cstk2 cr
  954.         ." fcstk: " printall: fcstk cr
  955.         ." fcstk2:" printall: fcstk2 cr
  956.         dasm
  957.     then
  958. ;
  959.  
  960. : FP_MONADIC_ARITH
  961.  
  962.     FPRs -> theRegs
  963.     1 foperands
  964.  
  965.     opnd1  ->: ivar> A_opnd in theOD
  966.  
  967.     compRegReg
  968.     free: opnd1
  969.     res1 fpush
  970.     GPRs -> theRegs        ¥ normal default - might be best to put it back
  971.  
  972.     debug? if
  973.         ." fp_monadic_arith finished:" cr
  974.         ." cstk:  " printall: cstk cr
  975.         ." cstk2: " printall: cstk2 cr
  976.         ." fcstk: " printall: fcstk cr
  977.         ." fcstk2:" printall: fcstk2 cr
  978.         dasm
  979.     then
  980. ;
  981.  
  982.  
  983. : DYADIC_ARITH
  984.     debug? if
  985.         cr
  986.         ." dyadic_arith -" cr
  987.         ." operation " operation .h  ."   subOperation " subOperation .h cr
  988.         printall: cstk
  989.     then
  990.  
  991.     GPRs -> theRegs
  992.     clear: instrn  clear: theOD
  993.     operation  put: ivar> opType in theOD
  994.     subOperation  put: ivar> subType in theOD
  995.  
  996.     operation otFPstart >= IF  FP_dyadic_arith  EXIT  THEN
  997.  
  998.     2 operands
  999.     refType: opnd1  litRef =  negate 2*
  1000.     refType: opnd2  litRef =  negate or
  1001.     
  1002.     SELECT[    0    ]=>            ¥ Both operands are regs
  1003.                     opnd1  ->: ivar> A_opnd in theOD
  1004.                     opnd2  ->: ivar> B_opnd in theOD
  1005.                     compRegReg
  1006.                     
  1007.           [    1    ]=>            ¥ 1st op reg, 2nd lit
  1008.                       compRegLit
  1009.           
  1010.           [    2    ]=>            ¥ 1st op lit, 2nd reg.  If the op is commutative, we can
  1011.                               ¥  just swap the operands and call compRegLit.  If it's
  1012.                               ¥  subtract, we can change it to subfic and do the same
  1013.                               ¥  thing.  Otherwise we have to do a bit more juggling so
  1014.                               ¥  we call nonCom_litReg to handle it.
  1015.                               
  1016.                       operation otSub =
  1017.                       IF        otSubfc -> operation  true
  1018.                       ELSE    operation  commutative?
  1019.                       THEN
  1020.                       
  1021.                       IF
  1022.                           opnd1 ->: res3  opnd2 ->: opnd1  res3 ->: opnd2
  1023.                           compRegLit
  1024.                       ELSE    
  1025.                           nonCom_litReg
  1026.                       THEN
  1027.           
  1028.           [    3    ]=>            ¥ Both lit - execute the op right now!
  1029.                       lit: opnd1  lit: opnd2
  1030.                       operation subOperation getImmediateOp  execute
  1031.                       >lit: res1
  1032.  
  1033.           DEFAULT=>  drop
  1034.     ]SELECT
  1035.     free: opnd1  free: opnd2
  1036.     res1 push
  1037.     true -> check_OP_stores?    ¥ may have been turned off
  1038. ;
  1039.  
  1040.  
  1041. : MONADIC_ARITH
  1042.     debug? if
  1043.         cr
  1044.         ." monadic_arith -" cr
  1045.         ." operation " operation .h  ."   subOperation " subOperation .h cr
  1046.         printall: cstk
  1047.     then
  1048.  
  1049.     GPRs -> theRegs
  1050.  
  1051.     clear: instrn  clear: theOD
  1052.     operation  put: ivar> opType in theOD
  1053.     subOperation  put: ivar> subType in theOD
  1054.  
  1055.     operation otFPstart >= IF  FP_monadic_arith  EXIT  THEN
  1056.  
  1057.     1 operands
  1058.     opnd1  ->: ivar> A_opnd in theOD
  1059.     
  1060.     true match&allocate?  ?EXIT        ¥ if it matches a result we already
  1061.                                     ¥  have, we reuse it
  1062.                                     
  1063.     cascade&match?  ?EXIT            ¥ If we can cascade it with a preceding
  1064.                                     ¥  op, we do it and we're done
  1065.     refType: opnd1
  1066.     SELECT[    gprRef    ]=>        gpr: opnd1  >Agpr: theOD
  1067.                             compRegReg
  1068.  
  1069.           [    fprRef    ]=>            to_be_written
  1070.  
  1071.           [    CRref    ]=>        operation otNOT =
  1072.                               IF        ¥ we can use a CR op
  1073.                                   compCRCR        ¥ this does everything
  1074.                                 res1 push   EXIT
  1075.                               ELSE
  1076.                                   opnd1 get_to_gpr? drop
  1077.                               THEN
  1078.                               gpr: opnd1  >Agpr: theOD
  1079.                               compRegReg
  1080.  
  1081.           [    litRef    ]=>            ¥ execute the op right now!
  1082.                                 lit: opnd1
  1083.                               operation subOperation getImmediateOp  execute
  1084.                               >lit: res1
  1085.  
  1086.     DEFAULT=>
  1087.     ]SELECT
  1088.  
  1089.     free: opnd1
  1090.     res1 push
  1091.     true -> check_OP_stores?    ¥ may have been turned off
  1092. ;
  1093.  
  1094.  
  1095. : special_arith?    ¥ handles things like subfze.  We only include the ones we 
  1096.                     ¥  actually want.  Also, as we're only generating them 
  1097.                     ¥  internally, we can kludge a bit, and assume the
  1098.                     ¥  operands are of the right sort.  We'll just get an error 
  1099.                     ¥  if they're not, which won't affect users.
  1100.     operation
  1101. ¥    SELECT[    otAddic        ],
  1102. ¥          [    otSubfic    ]=>        1 operands
  1103. ¥                                litref >reftype: opnd1        ¥ shd always be literal
  1104. ¥                                opnd1 push  dyadic_arith  true
  1105.     SELECT[    otAddze        ],
  1106.           [    otAddme        ],
  1107.           [    otSubfze    ],
  1108.           [    otSubfme    ]=>        0 >gpr: res1  res1 push
  1109.                                   dyadic_arith  true  
  1110.  
  1111.     ¥      [    otAddc        ],
  1112.     ¥      [    otAdde        ],
  1113.     ¥      [    otSubfc        ],
  1114.     ¥      [    otSubfe        ]=>
  1115.  
  1116.         DEFAULT=>  drop  false
  1117.     ]SELECT
  1118. ;
  1119.  
  1120.  
  1121. : DO_ARITH_OP
  1122.     special_arith?  ?EXIT        ¥ out if it was special, and we handled it
  1123.     operation monadic? nip
  1124.     IF  monadic_arith  ELSE  dyadic_arith  THEN
  1125. ;
  1126.  
  1127.  
  1128. : GENERATE_CR_RESULT  { ¥ reg# cr# wantit? -- }
  1129.  
  1130.     0 -> cr#  false -> wantit?
  1131.  
  1132.     Atype: theOD  FPRref =  IF  1 -> cr#  THEN
  1133.     
  1134.     reg: ivar> A_opnd in theOD  dup -> reg#  select: theRegs
  1135.     
  1136. (*    We first see if we can avoid a cmp by modifying the antecedent op to set
  1137.     CR0 (or CR1 if it's FP).  This situation is a bit like cascading, but a 
  1138.     bit different too.  The main difference is that if we modify the 
  1139.     antecedent to set CR0, we haven't actually changed its result, so its 
  1140.     refcnt and other uses of that reg don't matter.  But we do still have
  1141.     to check for a basic block boundary, since we can't rely on CR0 still
  1142.     being valid over such a boundary - in fact, it generally won't be.
  1143. *)
  1144.     get: ivar> opCDP in theRegs  basic_block_start  u>=
  1145.                             ¥ there's no BB boundary - if there is, we
  1146.                             ¥  can't optimize to use CR0/1, regardless
  1147.     IF
  1148.         get: ivar> instrnType in theRegs
  1149.         SELECT[    arithType        ],
  1150.               [ logicalType        ]=>            ¥ OK unless literal
  1151.                                         Btype: theRegs  litRef <>
  1152.         DEFAULT=>    drop false
  1153.         ]SELECT
  1154.     
  1155.         -> wantit?
  1156.     
  1157.     ¥ but there's one special exception - literal AND ( andi. ) always sets CR0
  1158.     ¥  no matter what!  Note, if we're in the FPRs, the op won't ever be otAnd,
  1159.     ¥  but the following test is still valid so we don't need to check for this case.
  1160.  
  1161.         wantit? 
  1162.         NIF
  1163.             get: ivar> opType in theRegs otAnd =
  1164.             Btype: theRegs  litRef =  and  -> wantit?
  1165.         THEN
  1166.     THEN
  1167.  
  1168.     wantit?  cr#
  1169.     get: ivar> opCDP in theRegs
  1170.     CR_result
  1171.  
  1172.     current: CRs cr# =  wantit? and
  1173.     IF                ¥ we can set the CR field by recompiling the op
  1174.         setCR: theRegs
  1175.         recompile: theRegs
  1176.         get: ivar> opCDP in theRegs  mark_use: theRegs
  1177.                             ¥ that was an implicit reference to that reg
  1178.  
  1179.     ELSE            ¥ we have to compile a cmp
  1180.         theOD ->: CRs
  1181.         compile: CRs
  1182.     THEN
  1183. ;
  1184.  
  1185.  
  1186. (*    modify_condition is called when a monadic condition reference references
  1187.     another condition reference (e.g. ... < 0= - doesn't look very logical,
  1188.     but inline code could cause this to happen).  The initial ref is in opnd1,
  1189.     and the conditional op is in subOperation.  The result ref goes into res1.
  1190.     The situation we're modelling is that the first op has left a flag on the
  1191.     data stack, which of course is -1 or 0.  So the possible transformations
  1192.     are:
  1193.         1st op        monadic op        result
  1194.         -1            0<>                -1
  1195.                     0=                0
  1196.                     0>=                0
  1197.                     0<                -1
  1198.                     0<=                -1
  1199.                     0>                0
  1200.         
  1201.         0            0<>                0
  1202.                     0=                -1
  1203.                     0>=                -1
  1204.                     0<                0
  1205.                     0<=                -1
  1206.                     0>                0
  1207.  
  1208.     That is, the condition is simply inverted for all ops except 0<= and 0>,
  1209.     which are left unchanged.
  1210. *)
  1211.  
  1212.  
  1213. : MODIFY_CONDITION
  1214.     addr: opnd1  ->: res1
  1215.     suboperation  cmpZLE =  suboperation  cmpZGT = or  ?EXIT
  1216.     not: ivar> 1_is_true? in res1
  1217. ;
  1218.  
  1219.  
  1220. : DYADIC_COMPARISON        ¥ ( unsigned? -- )
  1221.     ¥ Note: operation not set up yet.  The comparison code is in
  1222.     ¥  subOperation.
  1223.  
  1224.     debug? if
  1225.         ." dyadic_comparison -" cr
  1226.         ." subOperation " subOperation .h cr
  1227.     then
  1228.  
  1229.     GPRs -> theRegs
  1230.  
  1231.     clear: instrn  clear: theOD
  1232.     IF otUCMP ELSE otCMP THEN  dup -> operation
  1233.                     put: ivar> opType in theOD
  1234.     subOperation    put: ivar> subtype in theOD
  1235.  
  1236.     2 operands
  1237.     refType: opnd1  litRef =  negate 2*
  1238.     refType: opnd2  litRef =  negate or
  1239.     
  1240.     SELECT[    0    ]=>            ¥ Both operands are regs (GPR or CR)
  1241.  
  1242.                     opnd1 get_to_gpr? drop
  1243.                     opnd2 get_to_gpr? drop
  1244.  
  1245.                     gpr: opnd1  >Agpr: theOD
  1246.                     gpr: opnd2  >Bgpr: theOD
  1247.                     theOD  true  match?: CRs
  1248.                     IF    allocate: CRs
  1249.                         current: CRs  >CR: res1  subOperation >condition: res1
  1250.                         res1 ->: ivar> myRef in CRs
  1251.                     ELSE
  1252.                         false 0 0 CR_result
  1253.                         theOD ->: CRs
  1254.                         compile: CRs
  1255.                     THEN
  1256.                      
  1257.           [    1    ]=>            ¥ 1st op reg, 2nd lit
  1258.                       compRegLit
  1259.           
  1260.           [    2    ]=>            ¥ 1st op lit, 2nd reg
  1261.                       reverse_comparison
  1262.                       opnd1 ->: res3  opnd2 ->: opnd1  res3 ->: opnd2
  1263.                       compRegLit
  1264.           
  1265.           [    3    ]=>            ¥ Both lit
  1266.                       lit: opnd1  lit: opnd2
  1267.                       operation subOperation getImmediateOp  execute
  1268.                       >lit: res1
  1269.  
  1270.           DEFAULT=>  drop
  1271.     ]SELECT
  1272.     
  1273.     free: opnd1  free: opnd2
  1274.     res1 push
  1275.     true -> check_OP_stores?    ¥ may have been turned off
  1276. ;
  1277.  
  1278.  
  1279. : MONADIC_COMPARISON    ¥  ( unsigned? -- )
  1280.     ¥ Note: operation not set up yet.  The comparison code is in
  1281.     ¥  subOperation.
  1282.  
  1283.     GPRs -> theRegs
  1284.  
  1285.     clear: instrn  clear: theOD
  1286.     IF otUCMP ELSE otCMP THEN  dup -> operation
  1287.                     put: ivar> opType in theOD
  1288.     subOperation    put: ivar> subtype in theOD
  1289.     0  >Blit: theOD        ¥ second operand is literal zero
  1290.     1 operands
  1291.     refType: opnd1
  1292.  
  1293.     SELECT[    gprRef    ]=>            ¥ operand is in a gpr
  1294.                     gpr: opnd1  >Agpr: theOD
  1295.                     true match&allocate?
  1296.                     NIF
  1297.                         generate_CR_result
  1298.                     THEN
  1299.  
  1300.           [    crRef    ]=>        ¥ operand is in a cr so the test has been done - we
  1301.                               ¥  can just modify the existing reference
  1302.                               ¥  appropriately
  1303.                       modify_condition  res1 push  EXIT
  1304.  
  1305.           [    litRef    ]=>        ¥ execute the op right now!
  1306.                         lit: opnd1
  1307.                     operation subOperation getImmediateOp  execute
  1308.                       >lit: res1
  1309.  
  1310.           DEFAULT=>  drop
  1311.     ]SELECT
  1312.     
  1313.     free: opnd1
  1314.     res1 push
  1315. ;
  1316.  
  1317.  
  1318. : FP_DYADIC_COMPARISON
  1319.     debug? if
  1320.         ." fp_dyadic_comparison -" cr
  1321.         ." subOperation " subOperation .h cr
  1322.     then
  1323.     
  1324.     FPRs -> theRegs
  1325.  
  1326.     clear: instrn  clear: theOD
  1327.     otFPcmp  dup -> operation
  1328.                     put: ivar> opType in theOD
  1329.     subOperation    put: ivar> subtype in theOD
  1330.  
  1331.     2 foperands
  1332.  
  1333.     opnd1  ->: ivar> A_opnd in theOD
  1334.     opnd2  ->: ivar> B_opnd in theOD
  1335.  
  1336.     theOD  true  match?: CRs
  1337.     IF    allocate: CRs
  1338.         current: CRs  >CR: res1  subOperation >condition: res1
  1339.         res1 ->: ivar> myRef in CRs
  1340.     ELSE
  1341.         false 0 0 CR_result
  1342.         theOD ->: CRs
  1343.         compile: CRs
  1344.     THEN
  1345.  
  1346.     free: opnd1  free: opnd2
  1347.     res1 push
  1348.     true -> check_OP_stores?    ¥ may have been turned off
  1349.     GPRs -> theRegs                ¥ normal default - might be best to put it back
  1350.  
  1351.     debug? if
  1352.         ." fp_dyadic_comparison finished:" cr
  1353.         ." cstk:  " printall: cstk cr
  1354.         ." cstk2: " printall: cstk2 cr
  1355.         ." fcstk: " printall: fcstk cr
  1356.         ." fcstk2:" printall: fcstk2 cr
  1357.         dasm
  1358.     then
  1359. ;
  1360.  
  1361. : FP_MONADIC_COMPARISON
  1362.     debug? if
  1363.         ." fp_monadic_comparison -" cr
  1364.         ." subOperation " subOperation .h cr
  1365.     then
  1366.     
  1367.     FPRs -> theRegs
  1368.  
  1369.     clear: instrn  clear: theOD
  1370.     otFPcmp  dup -> operation
  1371.                     put: ivar> opType in theOD
  1372.     subOperation    put: ivar> subtype in theOD
  1373.  
  1374.     1 foperands
  1375.  
  1376.     fpr: opnd1  >Afpr: theOD
  1377.     true match&allocate?
  1378.     NIF
  1379.         generate_CR_result
  1380.     THEN
  1381.     free: opnd1
  1382.     res1 push
  1383.     
  1384.     true -> check_OP_stores?    ¥ may have been turned off
  1385.     GPRs -> theRegs                ¥ normal default - might be best to put it back
  1386.  
  1387.     debug? if
  1388.         ." fp_monadic_comparison finished:" cr
  1389.         ." cstk:  " printall: cstk cr
  1390.         ." cstk2: " printall: cstk2 cr
  1391.         ." fcstk: " printall: fcstk cr
  1392.         ." fcstk2:" printall: fcstk2 cr
  1393.         dasm
  1394.     then
  1395. ;
  1396.  
  1397. : SETUP_CONDITIONAL_BRANCH  { ^ref invert? ¥ whichBit -- }
  1398.     false -> check_OP_stores?    ¥ may be a reference_list instead of a reference,
  1399.     ^ref -> aRef                ¥  so we bypass the type check.
  1400.     true -> check_OP_stores?
  1401.     debug? if
  1402.         ." setup_conditional_branch called with "  print: aRef cr
  1403.     then
  1404.  
  1405.     16 >primOp: branch_instrn
  1406.  
  1407.     refType: aRef  CRref <>
  1408.     IF  ." ref passed to setup_conditional_branch not a CR ref" cr
  1409.         print: aRef  1 die
  1410.     THEN
  1411.  
  1412.     reg: aRef  4*  bit#: aRef or  -> whichBit
  1413.     true put: ivar> use_cond? in branch_instrn
  1414.     1_is_true?: aRef  invert? xor  put: ivar> branchOn1? in branch_instrn
  1415.     whichBit  >RA: branch_instrn
  1416. ;
  1417.  
  1418. ¥ : SETUP_UNCONDITIONAL_BRANCH
  1419. ¥    18 >primOp: uncond_branch_instrn
  1420. ¥    0  >lit: branch_instrn                ¥ for now - will be patched
  1421. ¥ ;
  1422.     
  1423. : COMPILE_UNCONDITIONAL_BRANCH
  1424. ¥    setup_unconditional_branch
  1425. ¥    compile: uncond_branch_instrn
  1426.     $ BF080000  code,
  1427. ;
  1428.  
  1429.  
  1430.  
  1431. (* COMBINE_BRANCHES is called when we have a conditional branch over a
  1432.    single unconditional branch or EXIT.  We can usually combine these
  1433.    into a single conditional branch.
  1434.    Note that a normal uncond. branch has the temp opcode BF08, an ELSE-
  1435.    branch has BF09, and an EXIT has BF02.  We don't use temp opcodes for
  1436.    conditional branches, so if we combine the branches and it's not an
  1437.    EXIT, we just emit a regular conditional branch.
  1438.  
  1439.    branchCDP is the addr of the 1st of the 2 branches.
  1440.    
  1441.    Note we only call this routine if the first branch is conditional.
  1442.    An ELSE branch can occur over another branch, but we handle that
  1443.    below in RESOLVE_ELSE.
  1444.    
  1445.    This also means we can assume here that branch_instrn is set up for
  1446.    the conditional branch, so we can easily invert the condition and
  1447.    recompile it.
  1448. *)
  1449.  
  1450. : COMBINE_BRANCHES  { branchCDP ¥ svCDP offs len -- }
  1451.     debug? if
  1452.         ." combine_branches called - there's a branch over "
  1453.     then
  1454.     CDP -> svCDP
  1455.     branchCDP 4+ w@
  1456.     CASE[    $ BF02    ]=>        ¥ it's an EXIT - marked by temp opcode BF02
  1457.                             ¥  until resolved at the end of the definition.  We
  1458.                             ¥  convert it to a conditional exit (opcode BF03).
  1459.                 debug? if
  1460.                     ." an EXIT" cr
  1461.                 then
  1462.                 branchCDP -> CDP
  1463.                 invert: branch_instrn  compile: branch_instrn
  1464.                 branchCDP @  16 >>  $ BF030000 or  branchCDP !  EXIT
  1465.  
  1466.         [ $ BF08 ], [ $ BF09 ]=>    ¥ uncond branch / ELSE-branch
  1467.                 debug? if
  1468.                     ." an uncond. branch" cr
  1469.                 then
  1470.                 branchCDP 2+ w@x  -> offs
  1471.                 offs 0EXIT            ¥ 2nd branch not resolved yet - can't combine
  1472.                 
  1473.         DEFAULT=>
  1474.     ]CASE
  1475.  
  1476.     ¥ We'll combine.  We need to retain the offset since we're going to
  1477.     ¥  move any following code to fill the gap, so the offset will stay
  1478.     ¥  the same.
  1479.  
  1480.     branchCDP -> CDP
  1481.     invert: branch_instrn  compile: branch_instrn
  1482. ¥    branchCDP  branchCDP 4+ offs +  resolve_branch
  1483.     offs  branchCDP 2+  w!
  1484.  
  1485. ¥ now if there's any code between that collapsed branch and the present
  1486. ¥  CDP position, we have to move it back by 4 bytes.  
  1487. ¥  ASSERT: there won't be a resolved branch pointing to anywhere in
  1488. ¥  the middle of the code we're moving!
  1489.  
  1490.     svCDP branchCDP 4+ -  -> len
  1491.     len 0>
  1492.     IF    branchCDP 8 + dup 4-  len  move        ¥ areas overlap, so don't use
  1493.                                             ¥  aligned_move
  1494.         svCDP 4-
  1495.     ELSE
  1496.         svCDP
  1497.     THEN  -> CDP
  1498. ;
  1499.  
  1500.  
  1501. : RESOLVE_ELSE  { branchCDP destCDP ¥ offs condCDP len wipeBoth? -- }
  1502.     destCDP branchCDP -  -> offs
  1503.     offs 4 =
  1504.     IF                    ¥ this is a branch to the next instruction - 
  1505.                         ¥  maybe we can just omit it altogether.
  1506.         destCDP CDP =  optimize_branches? and
  1507.         IF
  1508.             debug? if
  1509.                 ." ELSE branch over nothing - deleting it" cr
  1510.             then
  1511.  
  1512.         ¥ we pick up the offset to the original conditional branch and
  1513.         ¥ subtract 4 since we're deleting this branch.
  1514.         
  1515.             -4
  1516.             branchCDP 2+ w@x branchCDP + 2+
  1517.             w+!
  1518.             -4 ++> CDP  EXIT            ¥ wipe out the branch, and we're done
  1519.         THEN
  1520.     THEN
  1521.  
  1522. ¥ now we check if we're branching over another branch.  In this case,
  1523. ¥  we can get rid of both of them!
  1524.  
  1525.     false -> wipeBoth?
  1526.     offs 8 =  optimize_branches? and
  1527.  
  1528.     IF    branchCDP 4+ w@            ¥ these are the opcodes for our various
  1529.                                 ¥  kinds of unconditional branches:
  1530.         CASE[    $ BF02    ],            ¥ EXIT
  1531.             [    $ BF08    ],            ¥ normal uncond. branch
  1532.             [    $ BF09    ]=>            ¥ ELSE-branch
  1533.                 debug? if
  1534.                     ." ELSE branch over another branch - deleting both."  cr
  1535.                     ." Here's the code before we do:" cr
  1536.                     dasm
  1537.                 then
  1538.                 true -> wipeBoth?
  1539.                 
  1540.             DEFAULT=>    drop
  1541.  
  1542.         ]CASE
  1543.     THEN
  1544.  
  1545. ¥ now if we're compiling the ELSE branch, we resolve it and we're done.
  1546.  
  1547.     wipeBoth?
  1548.     NIF    offs $ FFFFFFFC and                ¥ %%%%temp while we're testing
  1549.         branchCDP 2+ w!  EXIT
  1550.     THEN
  1551.  
  1552. ¥ if we got here, we're omitting both the ELSE and the following
  1553. ¥  branch.
  1554.  
  1555. ¥ First we pick up the offset to the original conditional branch,
  1556. ¥ work out where it is, and compute the new offset to put in it,
  1557. ¥ so that it will branch to the target location of the following
  1558. ¥ branch, which is where it's going anyway.  Note we must allow
  1559. ¥ for the removal of the two branches, by reducing the offset by 8.
  1560.             
  1561.     branchCDP 2+ w@x branchCDP + -> condCDP
  1562.     branchCDP 6 + w@            ¥ offs to target, rel to branchCDP + 4
  1563.     branchCDP condCDP - + 4-     ¥ new offs, with 8 subtracted
  1564.     condCDP 2+  w!
  1565.  
  1566. ¥ If there's any code to move, we move it back by 8 bytes.  
  1567. ¥  ASSERT: there won't be a resolved branch pointing to anywhere in
  1568. ¥  the middle of the code we're moving!
  1569.  
  1570.     CDP branchCDP 8 + -  -> len
  1571.     len 0>
  1572.     IF    branchCDP 8 + dup 8 -  len  move        ¥ areas overlap, so don't use
  1573.     THEN                                    ¥  aligned_move
  1574.     8 --> CDP
  1575. ;
  1576.  
  1577.  
  1578. : RESOLVE_BRANCH  { branchCDP destCDP ¥ offs -- }
  1579.  
  1580.     branchCDP w@ $ BF09 =  optimize_branches? and
  1581.                                 ¥ is it an ELSE branch?
  1582.     IF                            ¥ yes - rather a special case, so we factor it out.
  1583.         branchCDP destCDP  resolve_ELSE  EXIT
  1584.     THEN
  1585.  
  1586.     destCDP branchCDP -  -> offs
  1587.  
  1588.     offs 4 =
  1589.     IF                    ¥ this is a branch to the next instruction - 
  1590.                         ¥  maybe we can just omit it altogether.
  1591.         destCDP CDP =  optimize_branches? and
  1592.         IF
  1593.             [ debug? ] [if]
  1594.                 ." conditional branch over nothing - deleting it" cr
  1595.             [then]
  1596.             -4 ++> CDP  EXIT        ¥ wipe out the branch, and we're done
  1597.         THEN
  1598.     THEN
  1599.  
  1600.     ¥ we resolve the branch:
  1601.  
  1602.     offs $ FFFFFFFC and                ¥ &&&&temp while we're testing
  1603.     branchCDP 2+ w!
  1604.  
  1605.     ¥ now if what we branched over was another branch instruction, we can
  1606.     ¥  combine them.
  1607.     
  1608.     offs 8 =  optimize_branches? and
  1609.  
  1610.     IF    branchCDP 4+ w@            ¥ these are the opcodes for our various
  1611.                                     ¥  kinds of unconditional branches:
  1612.         CASE[    $ BF02    ],            ¥ EXIT
  1613.             [    $ BF08    ],            ¥ normal uncond. branch
  1614.             [    $ BF09    ]=>            ¥ ELSE-branch
  1615.                 debug? if
  1616.                     ." conditional branch over another branch - combining them"  cr
  1617.                         ." here's the code before we do:" cr
  1618.                     dasm
  1619.                 then
  1620.                 branchCDP  combine_branches
  1621.             DEFAULT=>    drop
  1622.         ]CASE
  1623.     THEN
  1624. ;
  1625.  
  1626.  
  1627. : RESOLVE_UNCONDITIONAL_BRANCH  { branchCDP destCDP ¥ offs -- }
  1628.     ¥ We only use this for forward definitions and a couple of other
  1629.     ¥  related things.  So we don't do any fancy optimizations.
  1630.  
  1631.     destCDP branchCDP -  -> offs
  1632.     offs  $ 03FFFFFF and            ¥ uncond branches have 36-bit offset
  1633.     $ 48000000  or
  1634.     branchCDP !
  1635. [ ppc? ] [if]
  1636.     branchCDP 4  fix_caches
  1637. [then]
  1638. ;
  1639.  
  1640. endload
  1641.  
  1642. ¥ &&& not currently doing this, since we normally have to do some
  1643. ¥  register shuffling on return from a call.
  1644.  
  1645. : TAIL_OPTIMIZE?  { ¥ lookHere inst -- did_it? }
  1646.     false
  1647.     
  1648. ¥    CDP 4- -> lookHere
  1649. ¥    lookHere c@ 2 >> 18 =  0EXIT
  1650. ¥    lookHere @  -> inst
  1651. ¥    inst 1 and  0EXIT
  1652. ¥    inst 1 xor  lookHere !
  1653. ¥    drop true
  1654.  
  1655. ;
  1656.